from datetime import datetime
import time
from abc import ABC, abstractmethod
from typing import List

import pydantic
from fastapi_pagination.bases import AbstractPage
from fastapi_pagination.ext.databases import paginate
from sqlalchemy import insert, select, func, update
from forward.model.tables.article import ArticleCateGoryModel, ArticleModel
from forward.api.admin.schemas.article import (
    ArticleCateOutSchema,
    ArticleCateListInSchema,
    ArticleCateAddInSchema,
    ArticleCateEditInSchema,
    ArticleCateDetailInSchema,
    ArticleCateChangeInSchema,
    ArticleCateDeleteInSchema,
)
from forward.dependencies.database import db


class ArticleCateService:
    """
    文章分类服务实现类
    """

    async def find_cate_by_id(self, cate_id: int):
        """
        根据id返回指定cate
        :param cate_id:
        :return:
        """
        cate_record = await db.fetch_one(
            select(ArticleCateGoryModel)
            .select_from(ArticleCateGoryModel)
            .where(
                ArticleCateGoryModel.id == cate_id, ArticleCateGoryModel.is_delete == 0
            )
        )
        return ArticleCateOutSchema.model_validate(cate_record, from_attributes=True)

    async def all(self) -> List[ArticleCateOutSchema]:
        """
        所有文章分类
        :return:
        """
        query = (
            select(ArticleCateGoryModel)
            .select_from(ArticleCateGoryModel)
            .where(ArticleCateGoryModel.is_delete == 0)
            .order_by(ArticleCateGoryModel.sort)
        )
        all_cate = await db.fetch_all(query)
        return [
            ArticleCateOutSchema.model_validate(cate, from_attributes=True)
            for cate in all_cate
        ]

    async def list(
        self, list_in: ArticleCateListInSchema
    ) -> AbstractPage[ArticleCateOutSchema]:
        where = [ArticleCateGoryModel.is_delete == 0]
        if list_in.name:
            where.append(ArticleCateGoryModel.name.like("%{0}%".format(list_in.name)))
        if list_in.is_show is not None:
            where.append(ArticleCateGoryModel.is_show == list_in.is_show)
        query = (
            select(ArticleCateGoryModel)
            .select_from(ArticleCateGoryModel)
            .where(*where)
            .order_by(ArticleCateGoryModel.sort)
        )
        pager = await paginate(db, query)
        for obj in pager.lists:
            obj.number = await db.fetch_val(
                select(func.count(ArticleModel.id)).where(
                    ArticleModel.cid == obj.id, ArticleModel.is_delete == 0
                )
            )
        return pager

    async def detail(
        self, detail_in: ArticleCateDetailInSchema
    ) -> ArticleCateOutSchema:
        """
        分类详情
        :param detail_in:
        :return:
        """
        cate_detail = await self.find_cate_by_id(detail_in.id)
        assert cate_detail, "分类不存在！"
        return ArticleCateOutSchema.model_validate(cate_detail, from_attributes=True)

    async def add(self, add_in: ArticleCateAddInSchema) -> ArticleCateOutSchema:
        """
        分类新增
        :return:
        """
        create_cate = add_in.model_dump()

        query = insert(ArticleCateGoryModel).values(**create_cate)
        return await db.execute(query)

    async def edit(self, edit_in: ArticleCateEditInSchema) -> ArticleCateOutSchema:
        """
        分类编辑
        :return:
        """
        edit_cate = await self.find_cate_by_id(edit_in.id)
        assert edit_cate, "分类不存在"

        edit_dict = edit_in.model_dump()

        return await db.execute(
            update(ArticleCateGoryModel)
            .where(ArticleCateGoryModel.id == edit_in.id)
            .values(**edit_dict)
        )

    async def delete(
        self, delete_in: ArticleCateDeleteInSchema
    ) -> ArticleCateOutSchema:
        """
        分类删除
        :return:
        """
        delete_cate = await self.find_cate_by_id(delete_in.id)
        assert delete_cate, "分类不存在"
        # TODO: 检查有文章使用分类

        return await db.execute(
            update(ArticleCateGoryModel)
            .where(ArticleCateGoryModel.id == delete_in.id)
            .values(is_delete=1, deleted_time=datetime.now())
        )

    async def change(self, change_in: ArticleCateChangeInSchema):
        """
        分类状态
        :param change_in:
        :return:
        """
        change_cate = await self.find_cate_by_id(change_in.id)
        assert change_cate, "分类不存在"
        new_is_show = int(not bool(change_cate.is_show))
        return await db.execute(
            update(ArticleCateGoryModel)
            .where(ArticleCateGoryModel.id == change_in.id)
            .values(is_show=new_is_show)
        )

    @classmethod
    async def instance(cls):
        """实例化"""
        return cls()
